/**
 * @auth:Ning
 * purpose:This class work for manage sound which need load form external.
 * date:2009-5-30	
 *  
 * */
package com.components.sound
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Timer;
	
	public class SoundItem extends EventDispatcher implements I_Loadable
	{
		//START...
		
		//PROPERTY...
		private var url:String;		
		
		private var sound:Sound;
		
		private var soundChanel:SoundChannel;
				
		private var percent:Number;
		
		private var loop:int;
		
		private var easeIn:SoundEaseMangement;
		
		private var easeOut:SoundEaseMangement;
					
		//CONSTRUCTOR...
		public function SoundItem(url:String)
		{
			
			this.url = url;
			
			load();
							
		}
		
		//METHODS...
		
		//on sound is loading...
		private function soundProgressHandler(evt:ProgressEvent):void
		{
			
			this.dispatchEvent(evt);
			
			this.percent = evt.bytesLoaded / evt.bytesTotal;
			
		}
		
		//on sound load complete...
		private function soundCompleteHandler(evt:Event):void
		{
			
			this.dispatchEvent(evt);
						
		}
		
		//fade in...
		private function fadeIn():void
		{
			
			if(easeIn == null)
			{
				
				return;
				
			}
															
			this.soundEase(this.easeIn,0);
			
			var easeInTimer:Timer = new Timer(30,Math.ceil(this.easeIn.duration / 30));
			
			easeInTimer.addEventListener(TimerEvent.TIMER,easeInTimerHandler);
						
			easeInTimer.start();			
			
		}
		
		//ease in timer handler...
		private function easeInTimerHandler(evt:TimerEvent):void
		{
						
			var timer:Timer = evt.currentTarget as Timer;
			
			this.soundEase(this.easeIn,timer.currentCount);
						
		}
		
		//fade out...
		private function fadeOut():void
		{
			
			if(this.easeOut == null)
			{
				
				return;
				
			}
					
												
			this.soundEase(easeOut,0);
			
			var easeOutTimer:Timer = new Timer(30,Math.ceil(this.easeOut.duration / 30));
			
			easeOutTimer.addEventListener(TimerEvent.TIMER,easeOutTimerHandler);
								
			easeOutTimer.start();	
						
		}
		
		//ease out timer handler...
		private function easeOutTimerHandler(evt:TimerEvent):void
		{
			
			var timer:Timer = evt.currentTarget as Timer;
			
			this.soundEase(this.easeOut,timer.currentCount);
			
			
		}
		
		//on ease out timer complete...
		private function easeOutCompleteHandler(evt:TimerEvent):void
		{
			
			this.fadeOut();
			
		}
		
		//get new sound transform...
		private function soundEase(ease:SoundEaseMangement,count:uint):void
		{
			
			var sf:SoundTransform = new SoundTransform;
			
			if(!ease) return;
			
			for(var i:int = 0; i < ease.props.length;i++)
			{
				
				sf[ease.props[i]] = ease.values[i][0] + ((ease.values[i][1] - ease.values[i][0]) / Math.ceil(ease.duration / 30)) * count;
				
			}
			
			this.soundChanel.soundTransform = sf;
			
		}
		
		//sound play complete...
		private function soundPlayCompleteHandler(evt:Event):void
		{
			
			if(this.loop > 0)
			{
			
				this.dispatchEvent(evt);
			
			}else{
				
				this.play();
				
			}
					
		}
		
		//sound io error....
		private function soundIoErrorHandler(evt:IOErrorEvent):void
		{
			
			dispatchEvent(evt);
			
		}
						
		//start load mp3 form external, implements iLoadable interface...
		public function load():void
		{
			
			sound = new Sound(new URLRequest(url));
			
			sound.addEventListener(IOErrorEvent.IO_ERROR,soundIoErrorHandler);
			
			sound.addEventListener(ProgressEvent.PROGRESS,soundProgressHandler);
			
			sound.addEventListener(Event.COMPLETE,soundCompleteHandler);
			
		}
		
		//sound io error....
				
		//get how much percent of the map3 file loaded, implements iLoadable interface...
		public function isDone():Number
		{
			
			return this.percent;
		
		}
		
		//set volume...
		public function set volume(val:Number):void
		{
			
			var tf:SoundTransform  = new SoundTransform;
			
			tf.volume = val;
			
			this.soundChanel.soundTransform = tf;
			
		}
		
		//get volume...
		public function get volume():Number
		{
			
			return this.soundChanel.soundTransform.volume;
			
		}
		
		//play...
		public function play(loop:int = 0,easeIn:SoundEaseMangement = null,easeOut:SoundEaseMangement = null):void
		{
							
			this.easeIn = easeIn;
			
			this.easeOut = easeOut;
					
			this.loop = loop;
						
			soundChanel = sound.play(0,loop);
			
			this.soundChanel.addEventListener(Event.SOUND_COMPLETE,soundPlayCompleteHandler);
						
			fadeIn();
			
			if(this.easeOut is SoundEaseMangement)
			{
				
				var easeOutTimer:Timer = new Timer(this.sound.length * loop - this.easeOut.duration,1);
				
				easeOutTimer.addEventListener(TimerEvent.TIMER_COMPLETE,easeOutCompleteHandler);
				
				easeOutTimer.start();
				
			}
			
		}
			
		//get current position...
		public function get position():Number
		{
			
			return this.soundChanel.position;
			
		}
		
		//get total time...
		public function get totalTime():Number
		{
			
			return this.sound.length;
			
		}
		
		//stop...
		public function stop():void
		{
			
			this.soundChanel.stop();
			
		}
		
		//END	
	}
}